// =======================================================================
// 
//       Filename:  citerator.cpp
// 
//    Description:  
// 
//        Version:  1.0
//        Created:  25.03.2010 22:00:36
//       Revision:  none
//       Compiler:  g++
// 
//         Author:  Dominik 'domachine' Burgdörfer (-), dominik.burgdoerfer@googlemail.com
//        Company:  -
// 
// =======================================================================

#include "citerator.hpp"
#include <cstdio>

namespace webplodder {
    namespace utils {
        CIterator::CIterator()
            : mStream(0), mPosition(-1)
        {
            resetCache();
        }

        CIterator::CIterator(std::istream& stream) 
            : mStream(&stream), mPosition(-1)
        {
            resetCache();
        }

        CIterator& CIterator::moveForward() 
        {
            readNextChar();
            ++mPosition;

            return *this;
        }

        char CIterator::currentChar() 
        {
            readNextChar();
            return mCache[1];
        }

        char CIterator::nextChar()
        {
            readNextChar();
            if(mStream->good()) {
                return mCache[2];
            }
            else
                return EOF;
        }

        char CIterator::lastChar()
        {
            return mCache[0];
        }

        void CIterator::readNextChar()
        {
            if(mCachePos[2] == mPosition) {
                char ch;

                if(mStream->good()) {
                    ch = static_cast<char>(mStream->get());
                    updateCache(ch);

                    if(mCache[1] == -1) {
                        if(mStream->good()) {
                            ch = static_cast<char>(mStream->get());
                            ++mPosition;
                            updateCache(ch);
                        }
                    }
                }
            }
        }

        void CIterator::updateCache(char ch)
        {
            ++mCachePos[2];

            mCachePos[1] = mCachePos[2] - 1;
            mCachePos[0] = mCachePos[1] - 1;

            mCache[0] = mCache[1];
            mCache[1] = mCache[2];
            mCache[2] = ch;
        }

        bool CIterator::good() const
        {
            return mStream->good();
        }

        bool CIterator::eof() const
        {
            return mStream->eof();
        }

        long CIterator::position() const

        {
            return mPosition > -1 ? mPosition : (mPosition+1);
        }

        void CIterator::rewind()
        {
            mStream->seekg(0, std::istream::beg);
            resetCache();
        }

        void CIterator::setStream(std::istream& stream)
        {
            mStream = &stream;
            resetCache();
        }

        void CIterator::resetCache()
        {
            mPosition = -1;

            int i;
            for(i = 0; i < 3; ++i) {
                mCachePos[i] = -1;
                mCache[i] = -1;
            }
        }
    }
}
